package org.sun.log_manager_study.modules.utils;

import com.github.javafaker.Faker;

import lombok.extern.slf4j.Slf4j;

import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.sun.log_manager_study.modules.user.entity.User;
import org.sun.log_manager_study.modules.user.mapper.UserMapper;

@Component
@Slf4j
public class UserDataGenerator {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    public void generateAndInsertUsers() {
        long start = System.currentTimeMillis();

        Faker faker = new Faker(new Locale("en-US"));
        List<User> batch = new ArrayList<>();
        int total = 10000;
        int batchSize = 1000; // 每次插入 1000 条，防止 SQL 太长

        for (int i = 0; i < total; i++) {
            User user = new User();
            user.setUsername(faker.name().username());
            user.setEmail(faker.internet().emailAddress());
            user.setPassword(faker.internet().password(6, 12));
            batch.add(user);

            if (batch.size() == batchSize) {
                userMapper.insertBatch(batch);
                batch.clear();
            }
        }

        // 插入剩余的数据
        if (!batch.isEmpty()) {
            userMapper.insertBatch(batch);
        }

        long end = System.currentTimeMillis();
        log.info("✅ 批量插入 {} 条用户数据完成，耗时 {} ms", total, (end - start));
    }

    public void insertManyUsersOneByOne() {
        long start = System.currentTimeMillis();

        Faker faker = new Faker();
        for (int i = 0; i < 10000; i++) {
            User user = new User();
            user.setUsername(faker.name().username());
            user.setEmail(faker.internet().emailAddress());
            user.setPassword(faker.internet().password());

            userMapper.insertUser(user); // 每次插入一条
        }

        long end = System.currentTimeMillis();
        log.info("⚠️ 单条插入 {} 条用户数据完成，耗时 {} ms", 10000, (end - start));
    }

    public void generateAndInsertTenMillionUsersMultiThread() throws InterruptedException {
        long start = System.currentTimeMillis();

        int total = 10_000_000; // 一千万
        int batchSize = 5000; // 每批插入 5000
        int threadCount = 16; // 线程数（建议和连接池最大连接数一致）

        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        int chunkSize = total / threadCount; // 每个线程负责多少条

        CountDownLatch latch = new CountDownLatch(threadCount);

        for (int t = 0; t < threadCount; t++) {
            int startIndex = t * chunkSize;
            int endIndex = (t == threadCount - 1) ? total : (t + 1) * chunkSize;

            executor.submit(() -> {
                try (SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH, false)) {
                    UserMapper mapper = session.getMapper(UserMapper.class);

                    Faker faker = new Faker(new Locale("en-US"));
                    List<User> batch = new ArrayList<>(batchSize);

                    for (int i = startIndex; i < endIndex; i++) {
                        User user = new User();
                        user.setUsername(faker.name().username());
                        user.setEmail(faker.internet().emailAddress());
                        user.setPassword(faker.internet().password(6, 12));
                        batch.add(user);

                        if (batch.size() == batchSize) {
                            mapper.insertBatch(batch);
                            batch.clear();
                        }
                    }

                    if (!batch.isEmpty()) {
                        mapper.insertBatch(batch);
                    }

                    session.commit(); // ⚡ 每个线程独立提交事务
                    log.info("✅ {} 插入完成，范围 {} - {}", Thread.currentThread().getName(), startIndex, endIndex);
                } catch (Exception e) {
                    log.error("❌ 线程 {} 插入失败", Thread.currentThread().getName(), e);
                } finally {
                    latch.countDown();
                }
            });
        }

        latch.await();
        executor.shutdown();

        long end = System.currentTimeMillis();
        log.info("🎉 多线程批量插入 {} 条数据完成，总耗时 {} 秒", total, (end - start) / 1000);
    }

}
